﻿@page "/diagram/ports"

@using Syncfusion.Blazor.Diagrams
@using System.Collections.ObjectModel
@using Syncfusion.Blazor.DropDowns
@using Syncfusion.Blazor.Inputs
@using Newtonsoft.Json.Linq;

@inherits SampleBaseComponent;

<SampleDescription>
    <p>  This sample visualizes the process flow of publishing a book using connection points. Connection points are static points over the shapes that allow you to create connections among the shapes.</p>
    <p style="font-weight: bold;">A new blazor diagram component which provides better performance than the existing diagram control in Blazor WebAssembly App. It is available in preview mode. Check the samples <a target='_blank' href='diagramcomponent/flowchart'>here</a>.</p>
</SampleDescription>
<ActionDescription>
   <p> This example shows how to add connection ports to shapes. The <a target='_blank' href='https://blazor.syncfusion.com/documentation/diagram/ports/ports/'>DiagramPorts</a> property of the node defines the static connection ports. The <a target='_blank' href='https://blazor.syncfusion.com/documentation/diagram/ports/positioning/'>Offset</a>, <a target='_blank' href='https://blazor.syncfusion.com/documentation/diagram/ports/positioning/#horizontal-and-vertical-alignment'>HorizontalAlignment</a>, <a target='_blank' href='https://blazor.syncfusion.com/documentation/diagram/ports/positioning/#horizontal-and-vertical-alignment'>VerticalAlignment</a>, and <a target='_blank' href='https://blazor.syncfusion.com/documentation/diagram/ports/positioning/#margin'>Margin</a> properties of the port define its position.</p>
   <p>The <a target='_blank' href='https://blazor.syncfusion.com/documentation/diagram/ports/appearance/'>Style</a> property of the port can be used to customize its appearance. The <a target='_blank' href='https://blazor.syncfusion.com/documentation/diagram/ports/appearance/#visibility'>Visibility</a> property can also be used to define when the connection ports should be visible.</p>
</ActionDescription>

@*Hidden:Lines*@
<div class="content-wrapper" style="width: 100%">
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <div class="col-lg-9 control-section" style="border-right: 1px solid #D7D7D7">
        <style>
            .texstyle {
                display: table;
                height: 35px;
                padding-right: 4px;
                padding-left: 0px;
                width: 50%;
                padding-top: 10px;
                float: left;
                position: relative;
                min-height: 1px;
            }

            .row {
                margin-left: 0px;
                margin-right: 0px;
                display: block;
            }

            .e-bigger .e-btn.e-small.e-icon-btn {
                padding: 0px;
            }
        </style>
        @*End:Hidden*@
        <SfDiagram Height="@Height" @ref="@Diagram" Nodes="@NodeCollection" Connectors="@ConnectorCollection">
            <DiagramSnapSettings Constraints="@SnapConstraints.None"></DiagramSnapSettings>
            <DiagramEvents Created="@OnCreated" SelectionChanged="SelectionChange"></DiagramEvents>
            <DiagramPageSettings>
                <DiagramFitOptions CanFit="@true" Mode="FitModes.Page"></DiagramFitOptions>
            </DiagramPageSettings>
        </SfDiagram>
        @*Hidden:Lines*@
    </div>
    <div class="col-lg-3 property-section">
        <div class="property-panel-header">
            Properties
        </div>
        <div id="propertypanel" class="e-remove-selection">
            <div class="property-section-content property-panel-content">

                <div class="row" style="padding-top: 8px">
                    <div class="texstyle">
                        Visibility
                    </div>
                    <div class="col-xs-6">
                        <SfMultiSelect TValue="string[]" TItem="DiagramModel" Width="140px" @bind-Value="@MultiVal" AllowFiltering="@AllowFilteringValue" Placeholder="Select Visibility" Mode="VisualMode.CheckBox" DataSource="postVisibilityType" ShowSelectAll="false" ShowDropDownIcon="true" PopupHeight="280px" PopupWidth="180px">

                            <MultiSelectFieldSettings Text="Text" Value="Value"></MultiSelectFieldSettings>
                            <MultiSelectEvents TValue="string[]" TItem="DiagramModel" ValueChange="PortVisibilityDropOnChange"></MultiSelectEvents>
                        </SfMultiSelect>
                    </div>
                </div>
                <div class="row" style="padding-top: 8px">
                    <div class="texstyle">
                        Shape
                    </div>
                    <div class="col-xs-6">
                        <SfDropDownList TValue="string" Width="140px" TItem="DiagramShapeModel" @bind-Value="@selectedShape" DataSource="shape" @ref="@DropDownList" Placeholder="Select a Shape">
                            <DropDownListFieldSettings Text="Text" Value="Value"></DropDownListFieldSettings>
                            <DropDownListEvents TValue="string" TItem="DiagramShapeModel" ValueChange="PortShapeDropOnChange"></DropDownListEvents>
                        </SfDropDownList>
                    </div>
                </div>
                <div class="row" style="padding-top: 8px">
                    <div class="texstyle">
                        Stroke Width
                    </div>
                    <div class="col-xs-6">
                        <SfNumericTextBox @ref="@Widthtextbox" TValue="double" Width="140px" @bind-Value="@widthNumeric" Min="1" Step="0.5" Format="###.##">
                            <NumericTextBoxEvents TValue="double" ValueChange="OnBorderWidthChange"></NumericTextBoxEvents>
                        </SfNumericTextBox>
                    </div>
                </div>

                <div class="row" style="padding-top: 8px">
                    <div class="texstyle">
                        Size
                    </div>
                    <div class="col-xs-6">
                        <SfNumericTextBox @ref="@Sizetextbox" TValue="double" Width="140px" @bind-Value="@sizeNumeric" Min="1" Step="1" Format="###.##">
                            <NumericTextBoxEvents TValue="double" ValueChange="OnSizeChange"></NumericTextBoxEvents>
                        </SfNumericTextBox>
                    </div>
                </div>
                <div class="row" style="padding-top: 8px">
                    <div class="texstyle">
                        Port Color
                    </div>
                    <div class="col-xs-6">
                        <SfColorPicker  ValueChange="OnFillColorChange" @bind-Value="@fillColor"></SfColorPicker>
                    </div>
                </div>
                <div class="row" style="padding-top: 8px">
                    <div class="texstyle">
                        Stroke Color
                    </div>
                    <div class="col-xs-6">
                        <SfColorPicker ValueChange="OnBorderChange" @bind-Value="@strokeColor"></SfColorPicker>
                    </div>
                </div>
            </div>
        </div>
    </div>
    @*End:Hidden*@
</div>
@code {
    SfNumericTextBox<double> Widthtextbox;
    SfNumericTextBox<double> Sizetextbox;

    SfDiagram Diagram;
    Boolean AllowFilteringValue = false;

    SfDropDownList<string, DiagramShapeModel> DropDownList;
    public string[] MultiVal { get; set; } = new string[] { "Visible" };
    double sizeNumeric = 6;
    double widthNumeric = 1;
    string selectedShape = "Circle";
    string fillColor = "#366f8c";
    string strokeColor = "#366f8c";
    public string Height { get; set; } = "565px";

    public ObservableCollection<DiagramNode> NodeCollection
    {
        get;
        set;
    }

    public ObservableCollection<DiagramConnector> ConnectorCollection
    {
        get;
        set;
    }

    public void PortVisibilityDropOnChange(MultiSelectChangeEventArgs<string[]> args)
    {
        ApplyPortStyle("visibility", args.Value);
    }

    public void PortShapeDropOnChange(Syncfusion.Blazor.DropDowns.ChangeEventArgs<string, DiagramShapeModel> args)
    {
        ApplyPortStyle("shape", args.Value);
    }

    List<DiagramShapeModel> shape = new List<DiagramShapeModel>()
    {
        new DiagramShapeModel() { Value= "X", Text= "X" },
        new DiagramShapeModel()   { Value= "Circle", Text= "Circle" },
        new DiagramShapeModel() { Value= "Square", Text= "Square" },
        new DiagramShapeModel() { Value="Custom", Text= "Custom" }
    };

    List<DiagramModel> postVisibilityType = new List<DiagramModel>()
    {
        new DiagramModel() { Value= "Visible", Text= "Visible" },
        new DiagramModel() { Value= "Hover", Text= "Hover" },
        new DiagramModel() { Value= "Connect", Text= "Connect" }
    };
    public void OnBorderChange(ColorPickerEventArgs args)
    {
        ApplyPortStyle("strokecolor", args.CurrentValue.Hex);
    }

    public void OnBorderWidthChange(Syncfusion.Blazor.Inputs.ChangeEventArgs<double> args)
    {
        ApplyPortStyle("strokewidth", args.Value);
    }

    public void OnSizeChange(Syncfusion.Blazor.Inputs.ChangeEventArgs<double> args)
    {
        ApplyPortStyle("size", args.Value);
    }

    public string StyleValue = "background-color:#008000";

    public void OnFillColorChange(ColorPickerEventArgs args)
    {
        this.StyleValue = "background-color:" + args.CurrentValue.Hex;
        ApplyPortStyle("fill", args.CurrentValue.Hex);
        this.StateHasChanged();
    }


    public class DiagramModel
    {
        public string Value;
        public string Text;
    }

    public class DiagramShapeModel
    {
        public string Value { get; set; }
        public string Text { get; set; }
    }

    private void ApplyPortStyle(string propertyName, Object propertyValue)
    {
        if (Diagram.SelectedItems != null && Diagram.SelectedItems.Nodes != null && Diagram.SelectedItems.Nodes.Count > 0)
        {
            List<DiagramPort> ports = Diagram.SelectedItems.Nodes[0].Ports.ToList();
            for (int j = 0; j < ports.Count; j++)
            {
                DiagramPort port = ports[j];
                if (propertyName == "fill")
                {
                    port.Style.Fill = propertyValue.ToString();
                }
                else if (propertyName == "strokecolor")
                {
                    port.Style.StrokeColor = propertyValue.ToString();
                }
                else if (propertyName == "size")
                {
                    port.Width = port.Height = Convert.ToInt32(propertyValue);
                }
                else if (propertyName == "strokewidth")
                {
                    port.Style.StrokeWidth = Convert.ToInt32(propertyValue);
                }
                else if (propertyName == "visibility")
                {
                    port.Visibility = 0;
                    string[] propertyValue1 = propertyValue as string[];
                    if (propertyValue1 != null)
                    {
                        for (int i = 0; i < propertyValue1.Length; i++)
                        {
                            if (propertyValue1[i] == "Visible")
                            {
                                port.Visibility |= PortVisibility.Visible;
                            }
                            else if (propertyValue1[i] == "Hover")
                            {
                                port.Visibility |= PortVisibility.Hover;
                            }
                            else if (propertyValue1[i] == "Hidden")
                            {
                                port.Visibility |= PortVisibility.Hidden;
                            }
                            else if (propertyValue1[i] == "Connect")
                            {
                                port.Visibility |= PortVisibility.Connect;
                            }

                        }
                    }
                }
                else if (propertyName == "shape")
                {
                    port.Shape = (PortShapes)Enum.Parse(typeof(PortShapes), propertyValue.ToString());
                    if (propertyValue.ToString() == "Custom")
                    {
                        port.PathData = "M6.805,0L13.61,10.703L0,10.703z";
                    }
                }
            }
        }
    }

    private void SelectionChange(IBlazorSelectionChangeEventArgs arg)
    {
        if (arg.State == EventState.Changed)
        {
            if (arg.NewValue.Nodes != null && arg.NewValue.Nodes.Count > 0)
            {
                List<DiagramPort> ports = arg.NewValue.Nodes[0].Ports.ToList();
                if (ports.Count > 0)
                {
                    DiagramPort port = ports[0];
                    List<string> multiselect = new List<string>();
                    if ((port.Visibility & PortVisibility.Visible) != 0)
                    {
                        multiselect.Add("Visible");
                    }
                    if ((port.Visibility & PortVisibility.Hidden) != 0)
                    {
                        multiselect.Add("Hidden");
                    }
                    if ((port.Visibility & PortVisibility.Hover) != 0)
                    {
                        multiselect.Add("Hover");
                    }
                    if ((port.Visibility & PortVisibility.Connect) != 0)
                    {
                        multiselect.Add("Connect");
                    }
                    MultiVal = multiselect.ToArray();
                    selectedShape = port.Shape.ToString();
                    sizeNumeric = port.Width;
                    widthNumeric = port.Style.StrokeWidth;
                    //Widthtextbox.DataBind();
                    //Sizetextbox.DataBind();
                    fillColor = port.Style.Fill;
                    strokeColor = port.Style.StrokeColor;
                }
                StateHasChanged();
            }
        }
    }

    private void AddNode(string id, string content, List<DiagramPort> ports, double offsetX, double offsetY, BasicShapes shape)
    {
        DiagramNode node = new DiagramNode()
        {
            Id = id,
            Height = 65,
            Width = 100,
            OffsetX = offsetX,
            OffsetY = offsetY,
            Shape = new DiagramShape() { Type = Syncfusion.Blazor.Diagrams.Shapes.Basic, BasicShape = shape },
            Style = new NodeShapeStyle() { Fill = "#ebf8fb", StrokeColor = "#baeaf5" },
            Annotations = new ObservableCollection<DiagramNodeAnnotation>() { new DiagramNodeAnnotation() { Content = content, Style = new AnnotationStyle() { FontSize = 13, Color = "black" } } },
            Ports = new ObservableCollection<DiagramPort>(ports)

        };
        NodeCollection.Add(node);
    }

    private void AddConnector(string id, string sourceId, string sourcePortId, string targetId, string targetPortId)
    {
        DiagramConnector connector = new DiagramConnector()
        {
            Id = id,
            SourceID = sourceId,
            SourcePortID = sourcePortId,
            TargetID = targetId,
            TargetPortID = targetPortId,
            Type = Syncfusion.Blazor.Diagrams.Segments.Orthogonal,
            Style = new ConnectorShapeStyle() { StrokeColor = "#8cdcef", StrokeWidth = 1 },
            TargetDecorator = new ConnectorTargetDecorator()
            {
                Width = 5,
                Height = 5,
                Shape = DecoratorShapes.Arrow,
                Style = new DecoratorShapeStyle() { Fill = "#8cdcef", StrokeColor = "#8cdcef" }
            }
        };
        ConnectorCollection.Add(connector);
    }

    private DiagramPort AddPort(string id, double x, double y)
    {
        return new DiagramPort()
        {
            Id = id,
            Shape = PortShapes.Circle,
            Width = 6,
            Height = 6,
            Visibility = PortVisibility.Visible,
            Offset = new NodePortOffset() { X = x, Y = y },
            Style = new PortShapeStyle() { Fill = "#366f8c", StrokeColor = "#366f8c" }
        };
    }

    protected override void OnInitialized()
    {
        NodeCollection = new ObservableCollection<DiagramNode>();
        #region Ports
        List<DiagramPort> node1ports = new List<DiagramPort>();
        node1ports.Add(AddPort("port1", 0.01, 0.5));
        node1ports.Add(AddPort("port2", 1, 0.5));
        node1ports.Add(AddPort("port3", 0.25, 1));
        node1ports.Add(AddPort("port4", 0.5, 1));
        node1ports.Add(AddPort("port5", 0.75, 1));

        List<DiagramPort> node2ports = new List<DiagramPort>();
        node2ports.Add(AddPort("port6", 0.01, 0.5));
        node2ports.Add(AddPort("port7", 1, 0.35));
        node2ports.Add(AddPort("port8", 1, 0.7));
        node2ports.Add(AddPort("port9", 0.5, 1));

        List<DiagramPort> node3ports = new List<DiagramPort>();
        node3ports.Add(AddPort("port10", 0.01, 0.5));
        node3ports.Add(AddPort("port11", 0.5, 0.01));
        node3ports.Add(AddPort("port12", 0.5, 1));

        List<DiagramPort> node4ports = new List<DiagramPort>();
        node4ports.Add(AddPort("port13", 0.01, 0.5));
        node4ports.Add(AddPort("port14", 0.5, 0.01));
        node4ports.Add(AddPort("port15", 0.5, 1));

        List<DiagramPort> node5ports = new List<DiagramPort>();
        node5ports.Add(AddPort("port16", 0.01, 0.5));
        node5ports.Add(AddPort("port17", 0.5, 0.01));
        node5ports.Add(AddPort("port18", 1, 0.5));

        List<DiagramPort> node6ports = new List<DiagramPort>();
        node6ports.Add(AddPort("port19", 0.01, 0.35));
        node6ports.Add(AddPort("port20", 0.5, 1));

        List<DiagramPort> node7ports = new List<DiagramPort>();
        node7ports.Add(AddPort("port21", 0.5, 0.01));
        node7ports.Add(AddPort("port22", 0.5, 1));

        #endregion

        #region Nodes
        AddNode("node1", "Publisher", node1ports, 200, 100, BasicShapes.Rectangle);
        AddNode("node2", "Completed book", node2ports, 400, 100, BasicShapes.Rectangle);
        AddNode("node3", "First review", node3ports, 400, 200, BasicShapes.Diamond);
        AddNode("node4", "Legal terms", node4ports, 400, 300, BasicShapes.Rectangle);
        AddNode("node5", "Second review", node5ports, 400, 400, BasicShapes.Diamond);
        AddNode("node6", "Board", node6ports, 600, 100, BasicShapes.Rectangle);
        AddNode("node7", "Approval", node7ports, 600, 200, BasicShapes.Diamond);

        #endregion

        #region Connectors
        ConnectorCollection = new ObservableCollection<DiagramConnector>();
        AddConnector("connector1", "node1", "port2", "node2", "port6");
        AddConnector("connector2", "node1", "port4", "node4", "port13");
        AddConnector("connector3", "node2", "port9", "node3", "port11");
        AddConnector("connector4", "node2", "port7", "node6", "port19");
        AddConnector("connector5", "node3", "port10", "node1", "port5");
        AddConnector("connector6", "node3", "port12", "node4", "port14");
        AddConnector("connector7", "node4", "port15", "node5", "port17");
        AddConnector("connector8", "node5", "port18", "node2", "port8");
        AddConnector("connector9", "node5", "port16", "node1", "port3");
        AddConnector("connector10", "node6", "port20", "node7", "port21");
        AddConnector("connector11", "node7", "port22", "node1", "port1");
        #endregion
    }

    private async void OnCreated(object obj)
    {
        await Diagram.Select(new ObservableCollection<DiagramNode>() { Diagram.Nodes[0] }, null);
    }
}
